package omg.SongHandling.DataHandling;

import java.lang.reflect.InvocationTargetException;
import java.net.URI;
import java.util.logging.Level;
import java.util.logging.Logger;
import omg.Error.NoConnectionError;
import omg.Error.NoValidParserError;
import omg.Error.ParserCreationFailedError;

public class ParserManager {

        private static ParserManager instance = null;
        private static String parserPackage = "omg.SongHandling.DataHandling";
	private static String[] registeredParsers = {"ParserYouTube"};

        /* SINGLETON PATTERN */
        private ParserManager() {}
	public static ParserManager getInstance() {
            if (null == ParserManager.instance)
                ParserManager.instance = new ParserManager();
            return ParserManager.instance;
	}

	/**
	 * Iterates through all Parsers known to the class and returns the first
         * one feeling responsible for the supplied URI.
	 * @param uri the uri to parse
         * @return the suitable Parse initiated with the uri
         * @throws NoValidParserError if no fitting Parser could be found
         * @throws NoConnectionError if no connection to the uri target could be established
	 */
	public Parser getParser(URI uri) throws NoValidParserError, NoConnectionError {
            for (String parser : ParserManager.registeredParsers) {
                try {
                    // get class to use dynamic method call and object creation
                    Class cl = Class.forName(parserPackage + '.' + parser);
                    if ((Boolean) cl.getMethod("isResponsibleFor", URI.class).invoke(null, uri))
                        return (Parser) cl.getConstructor(URI.class).newInstance(uri);
                } catch (IllegalAccessException ex) {
                    Logger.getLogger("Periphery").log(Level.WARNING, parser + " constructor(java.net.URI) or isResponsibleFor(java.net.URI) is declared private/protected", ex);
                } catch (IllegalArgumentException ex) {
                    Logger.getLogger("Periphery").log(Level.WARNING, parser + " constructor(java.net.URI) or isResponsibleFor(java.net.URI) requires wrong arguments", ex);
                } catch (InvocationTargetException ex) {
                    if (NoConnectionError.class == ex.getCause().getClass())
                        throw (NoConnectionError)ex.getCause();
                    else if (ParserCreationFailedError.class == ex.getCause().getClass())
                        Logger.getLogger("Periphery").log(Level.WARNING, parser + " constructor(java.net.URI) caused an controlled exception", ex.getCause());
                    else
                        Logger.getLogger("Periphery").log(Level.WARNING, parser + " constructor(java.net.URI) caused an unexpected exception", ex.getCause());
                } catch (NoSuchMethodException ex) {
                    Logger.getLogger("Periphery").log(Level.WARNING, parser + " constructor(java.net.URI) or isResponsibleFor(java.net.URI) doesn't exist");
                } catch (ClassNotFoundException ex) {
                    Logger.getLogger("Periphery").log(Level.WARNING, parser + " is registered as known parser, but the class couldn't be found");
                } catch (Exception ex) {
                    Logger.getLogger("Periphery").log(Level.WARNING, parser + " contains some not nearer specified error",  ex);
                }
            }
            throw new NoValidParserError();
	}

}